using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace nToolbox.IO
{
	public static class FileHelper
	{
		public static void MakeWriteable(string path)
		{
			FileInfo fi = new FileInfo(path);
			if (fi.Exists)
			{
				FileAttributes attrs = fi.Attributes;
				fi.Attributes = attrs & ~FileAttributes.ReadOnly;
			}
		}

		/// <summary>
		/// Compare two files byte-by-byte
		/// </summary>
		/// <remarks>
		/// Code taken from http://support.microsoft.com/default.aspx?scid=kb;EN-US;320348
		/// </remarks>
		// This method accepts two strings the represent two files to 
		// compare. A return value of 0 indicates that the contents of the files
		// are the same. A return value of any other value indicates that the 
		// files are not the same.
		public static bool Compare(string file1, string file2)
		{
			// Determine if the same file was referenced two times.
			if (file1 == file2)
			{
				// Return true to indicate that the files are the same.
				return true;
			}

			// Open the two files.
			FileStream fs1;
			FileStream fs2;
			fs1 = new FileStream(file1, FileMode.Open, FileAccess.Read, FileShare.Read);
			fs2 = new FileStream(file2, FileMode.Open, FileAccess.Read, FileShare.Read);

			// Check the file sizes. If they are not the same, the files 
			// are not the same.
			if (fs1.Length != fs2.Length)
			{
				// Close the file
				fs1.Close();
				fs2.Close();

				// Return false to indicate files are different
				return false;
			}

			// Read and compare a byte from each file until either a
			// non-matching set of bytes is found or until the end of
			// file1 is reached.
			int file1byte;
			int file2byte;
			do
			{
				// Read one byte from each file.
				file1byte = fs1.ReadByte();
				file2byte = fs2.ReadByte();
			} while ((file1byte == file2byte) && (file1byte != -1));

			// Close the files.
			fs1.Close();
			fs2.Close();

			// Return the success of the comparison. "file1byte" is 
			// equal to "file2byte" at this point only if the files are 
			// the same.
			return ((file1byte - file2byte) == 0);
		}

		public static IList<string> ReadTextLines(string filename)
		{
			List<string> items = new List<string>();
			using (StreamReader sr = new StreamReader(filename))
			{
				string line;
				while ((line = sr.ReadLine()) != null)
				{
					line = line.Trim();
					if (line != "") items.Add(line);
				}
			}
			return items;
		}

		public static string ReadTextFile(string filename)
		{
			if (!File.Exists(filename))
				throw new ArgumentException("File does not exist.", "filename");

			using (FileStream stream = File.OpenRead(filename))
			{
				StreamReader reader = new StreamReader(stream, Encoding.Default, true);
				return reader.ReadToEnd();
			}
		}

        /// <summary>
        /// Read a text file and obtain it's contents.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <returns>String containing the content of the file.</returns>
        public static string GetFileText(string absolutePath)
        {
            using (StreamReader sr = new StreamReader(absolutePath))
                return sr.ReadToEnd();
        }

        /// <summary>
        /// Creates or opens a file for writing and writes text to it.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="fileText">A String containing text to be written to the file.</param>
        public static void CreateToFile(string absolutePath, string fileText)
        {
            using (StreamWriter sw = File.CreateText(absolutePath))
                sw.Write(fileText);
        }

        /// <summary>
        /// Update text within a file by replacing a substring within the file.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="lookFor">A String to be replaced.</param>
        /// <param name="replaceWith">A String to replace all occurrences of lookFor.</param>
        public static void UpdateFileText(string absolutePath, string lookFor, string replaceWith)
        {
            string newText = GetFileText(absolutePath).Replace(lookFor, replaceWith);
            WriteToFile(absolutePath, newText);
        }

        /// <summary>
        /// Writes out a string to a file.
        /// </summary>
        /// <param name="absolutePath">The complete file path to write to.</param>
        /// <param name="fileText">A String containing text to be written to the file.</param>
        public static void WriteToFile(string absolutePath, string fileText)
        {
            using (StreamWriter sw = new StreamWriter(absolutePath, false))
                sw.Write(fileText);
        }

        /// <summary>
        /// Display bytes as a suitable unit of measurement.
        /// </summary>
        /// <remarks>
        /// Uses 1024^x for the units as used by memory and file sizing. Do not use in
        /// telecommunications where 1000^x is the norm.
        /// </remarks>
        /// <param name="bytes">Number of bytes to display.</param>
        /// <returns>A String formatted with the number of bytes and suitable unit of measurement.</returns>
        public static string FromByteCount(long bytes)
        {
            const decimal kilobyte = 1024m;
            const decimal megabyte = kilobyte * 1024;
            const decimal gigabyte = megabyte * 1024;

            if (bytes > gigabyte)
                return String.Format("{0:0.00} GB", bytes / gigabyte);
            if (bytes > megabyte)
                return String.Format("{0:0.00} MB", bytes / megabyte);
            if (bytes > kilobyte)
                return String.Format("{0:0.00} KB", bytes / kilobyte);
            return String.Format("{0} B", bytes);
        }
	}
}